package com.zzh.lib.core.listener.impl;


import android.content.Context;
import android.database.Cursor;
import android.os.Build;
import android.os.Bundle;
import android.provider.MediaStore;
import android.text.TextUtils;

import com.zzh.lib.core.listener.HFilterResultCallback;
import com.zzh.lib.core.loader.HAudioLoader;
import com.zzh.lib.core.loader.HFileLoader;
import com.zzh.lib.core.loader.HImageLoader;
import com.zzh.lib.core.loader.HVideoLoader;
import com.zzh.lib.core.model.HAudioFileModel;
import com.zzh.lib.core.model.HDirectoryModel;
import com.zzh.lib.core.model.HFileModel;
import com.zzh.lib.core.model.HImageFileModel;
import com.zzh.lib.core.model.HVideoFileModel;
import com.zzh.lib.core.utils.HFileUtils;
import com.zzh.lib.core.utils.LogUtils;

import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import androidx.loader.app.LoaderManager;
import androidx.loader.content.CursorLoader;
import androidx.loader.content.Loader;

import static android.provider.BaseColumns._ID;
import static android.provider.MediaStore.Files.FileColumns.MIME_TYPE;
import static android.provider.MediaStore.MediaColumns.DATA;
import static android.provider.MediaStore.MediaColumns.DATE_ADDED;
import static android.provider.MediaStore.MediaColumns.DISPLAY_NAME;
import static android.provider.MediaStore.MediaColumns.SIZE;
import static android.provider.MediaStore.MediaColumns.TITLE;
import static com.zzh.lib.core.utils.HMediaUtils.TYPE_AUDIO;
import static com.zzh.lib.core.utils.HMediaUtils.TYPE_FILE;
import static com.zzh.lib.core.utils.HMediaUtils.TYPE_IMAGE;
import static com.zzh.lib.core.utils.HMediaUtils.TYPE_VIDEO;

/**
 * Created by ZZH on 2023/2/1.
 *
 * @date: 2023/2/1 21:58
 * @email: zzh_hz@126.com
 * @author: zzh
 * @description: com.zzh.lib.core.listener
 */
public class HFileLoaderCallbacks implements LoaderManager.LoaderCallbacks<Cursor> {

    private WeakReference<Context> context;
    private HFilterResultCallback resultCallback;

    private int mType = TYPE_IMAGE;
    private String[] mSuffixArgs;
    private CursorLoader mLoader;
    private String mSuffixRegex;

    public HFileLoaderCallbacks(Context context, HFilterResultCallback resultCallback, int type) {
        this(context, resultCallback, type, null);
    }

    public HFileLoaderCallbacks(Context context, HFilterResultCallback resultCallback, int type, String[] suffixArgs) {
        this.context = new WeakReference<>(context);
        this.resultCallback = resultCallback;
        this.mType = type;
        this.mSuffixArgs = suffixArgs;
        if (suffixArgs != null && suffixArgs.length > 0) {
            mSuffixRegex = obtainSuffixRegex(suffixArgs);
        }
    }

    @Override
    public Loader<Cursor> onCreateLoader(int id, Bundle args) {
        switch (mType) {
            case TYPE_IMAGE:
                mLoader = new HImageLoader(context.get());
                break;
            case TYPE_VIDEO:
                mLoader = new HVideoLoader(context.get());
                break;
            case TYPE_AUDIO:
                mLoader = new HAudioLoader(context.get());
                break;
            case TYPE_FILE:
                mLoader = new HFileLoader(context.get());
                break;
        }

        return mLoader;
    }

    @Override
    public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
        if (data == null) return;
        switch (mType) {
            case TYPE_IMAGE:
                onImageResult(data);
                break;
            case TYPE_VIDEO:
                onVideoResult(data);
                break;
            case TYPE_AUDIO:
                onAudioResult(data);
                break;
            case TYPE_FILE:
                onFileResult(data);
                break;
        }
    }

    @Override
    public void onLoaderReset(Loader<Cursor> loader) {

    }

    @SuppressWarnings("unchecked")
    private void onImageResult(Cursor data) {
        List<HDirectoryModel<HImageFileModel>> directories = new ArrayList<>();

        if (data.getPosition() != -1) {
            data.moveToPosition(-1);
        }

        while (data.moveToNext()) {
            //Create a File instance
            HImageFileModel img = new HImageFileModel();
            img.setId(data.getLong(data.getColumnIndexOrThrow(_ID)));
            img.setName(data.getString(data.getColumnIndexOrThrow(TITLE)));
            img.setPath(data.getString(data.getColumnIndexOrThrow(DATA)));
            img.setSize(data.getLong(data.getColumnIndexOrThrow(SIZE)));
            img.setBucketId(data.getString(data.getColumnIndexOrThrow(MediaStore.Images.Media.BUCKET_ID)));
            img.setBucketName(data.getString(data.getColumnIndexOrThrow(MediaStore.Images.Media.BUCKET_DISPLAY_NAME)));
            img.setDate(data.getLong(data.getColumnIndexOrThrow(DATE_ADDED)));
            img.setOrientation(data.getInt(data.getColumnIndexOrThrow(MediaStore.Images.Media.ORIENTATION)));
            img.setMimeType(data.getString(data.getColumnIndexOrThrow(MediaStore.Images.Media.MIME_TYPE)));
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
                img.setAuthor(data.getString(data.getColumnIndexOrThrow(MediaStore.Images.Media.AUTHOR)));
            }
            img.setDisplayName(data.getString(data.getColumnIndexOrThrow(DISPLAY_NAME)));

            //Create a Directory
            HDirectoryModel<HImageFileModel> directory = new HDirectoryModel<>();
            directory.setId(img.getBucketId());
            directory.setName(img.getBucketName());
            directory.setPath(HFileUtils.extractPathWithoutSeparator(img.getPath()));

            if (!directories.contains(directory)) {
                directory.addFile(img);
                directories.add(directory);
            } else {
                directories.get(directories.indexOf(directory)).addFile(img);
            }
        }

        if (resultCallback != null) {
            resultCallback.onResult(directories);
        }
    }

    @SuppressWarnings("unchecked")
    private void onVideoResult(final Cursor data) {
        List<HDirectoryModel<HVideoFileModel>> directories = new ArrayList<>();

        if (data.getPosition() != -1) {
            data.moveToPosition(-1);
        }

        while (data.moveToNext()) {
            //Create a File instance
            HVideoFileModel video = new HVideoFileModel();
            video.setId(data.getLong(data.getColumnIndexOrThrow(MediaStore.Video.VideoColumns._ID)));
            video.setName(data.getString(data.getColumnIndexOrThrow(MediaStore.Video.VideoColumns.TITLE)));
            video.setPath(data.getString(data.getColumnIndexOrThrow(MediaStore.Video.VideoColumns.DATA)));
            video.setSize(data.getLong(data.getColumnIndexOrThrow(MediaStore.Video.VideoColumns.SIZE)));
            video.setBucketId(data.getString(data.getColumnIndexOrThrow(MediaStore.Video.VideoColumns.BUCKET_ID)));
            video.setBucketName(data.getString(data.getColumnIndexOrThrow(MediaStore.Video.VideoColumns.BUCKET_DISPLAY_NAME)));
            video.setDate(data.getLong(data.getColumnIndexOrThrow(MediaStore.Video.VideoColumns.DATE_ADDED)));

            video.setDuration(data.getLong(data.getColumnIndexOrThrow(MediaStore.Video.VideoColumns.DURATION)));
            video.setMimeType(data.getString(data.getColumnIndexOrThrow(MediaStore.Video.VideoColumns.MIME_TYPE)));

            //Create a Directory
            HDirectoryModel<HVideoFileModel> directory = new HDirectoryModel<>();
            directory.setId(video.getBucketId());
            directory.setName(video.getBucketName());
            directory.setPath(HFileUtils.extractPathWithoutSeparator(video.getPath()));

            if (!directories.contains(directory)) {
                directory.addFile(video);
                directories.add(directory);
            } else {
                directories.get(directories.indexOf(directory)).addFile(video);
            }
        }

        if (resultCallback != null) {
            resultCallback.onResult(directories);
        }
    }

    @SuppressWarnings("unchecked")
    private void onAudioResult(Cursor data) {
        List<HDirectoryModel<HAudioFileModel>> directories = new ArrayList<>();

        if (data.getPosition() != -1) {
            data.moveToPosition(-1);
        }

        while (data.moveToNext()) {
            //Create a File instance
            HAudioFileModel audio = new HAudioFileModel();
            audio.setId(data.getLong(data.getColumnIndexOrThrow(MediaStore.Audio.Media._ID)));
            audio.setName(data.getString(data.getColumnIndexOrThrow(MediaStore.Audio.Media.TITLE)));
            audio.setPath(data.getString(data.getColumnIndexOrThrow(MediaStore.Audio.Media.DATA)));
            audio.setSize(data.getLong(data.getColumnIndexOrThrow(MediaStore.Audio.Media.SIZE)));
            audio.setDate(data.getLong(data.getColumnIndexOrThrow(MediaStore.Audio.Media.DATE_ADDED)));
            audio.setDisplayName(data.getString(data.getColumnIndexOrThrow(MediaStore.Audio.Media.DISPLAY_NAME)));
            audio.setAlbum(data.getString(data.getColumnIndexOrThrow(MediaStore.Audio.Media.ALBUM)));
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
                audio.setAlbumArtist(data.getString(data.getColumnIndexOrThrow(MediaStore.Audio.Media.ALBUM_ARTIST)));
                audio.setAuthor(data.getString(data.getColumnIndexOrThrow(MediaStore.Audio.Media.AUTHOR)));
            }
            audio.setArtist(data.getString(data.getColumnIndexOrThrow(MediaStore.Audio.Media.ARTIST)));
            audio.setDuration(data.getLong(data.getColumnIndexOrThrow(MediaStore.Audio.Media.DURATION)));
            audio.setMimeType(data.getString(data.getColumnIndexOrThrow(MediaStore.MediaColumns.MIME_TYPE)));

            //Create a Directory
            HDirectoryModel<HAudioFileModel> directory = new HDirectoryModel<>();
            directory.setName(HFileUtils.extractFileNameWithSuffix(HFileUtils.extractPathWithoutSeparator(audio.getPath())));
            directory.setPath(HFileUtils.extractPathWithoutSeparator(audio.getPath()));

            if (!directories.contains(directory)) {
                directory.addFile(audio);
                directories.add(directory);
            } else {
                directories.get(directories.indexOf(directory)).addFile(audio);
            }
        }

        if (resultCallback != null) {
            resultCallback.onResult(directories);
        }
    }

    @SuppressWarnings("unchecked")
    private void onFileResult(Cursor data) {
        List<HDirectoryModel<HFileModel>> directories = new ArrayList<>();

        if (data.getPosition() != -1) {
            data.moveToPosition(-1);
        }

        while (data.moveToNext()) {
            String path = data.getString(data.getColumnIndexOrThrow(DATA));
            if (path != null && contains(path)) {
                //Create a File instance
                HFileModel file = new HFileModel();
                file.setId(data.getLong(data.getColumnIndexOrThrow(_ID)));
                file.setName(data.getString(data.getColumnIndexOrThrow(TITLE)));
                file.setPath(data.getString(data.getColumnIndexOrThrow(DATA)));
                file.setSize(data.getLong(data.getColumnIndexOrThrow(SIZE)));
                file.setDate(data.getLong(data.getColumnIndexOrThrow(DATE_ADDED)));

                file.setMimeType(data.getString(data.getColumnIndexOrThrow(MIME_TYPE)));

                //Create a Directory
                HDirectoryModel<HFileModel> directory = new HDirectoryModel<>();
                directory.setName(HFileUtils.extractFileNameWithSuffix(HFileUtils.extractPathWithoutSeparator(file.getPath())));
                directory.setPath(HFileUtils.extractPathWithoutSeparator(file.getPath()));

                if (!directories.contains(directory)) {
                    directory.addFile(file);
                    directories.add(directory);
                } else {
                    directories.get(directories.indexOf(directory)).addFile(file);
                }
            }
        }

        if (resultCallback != null) {
            resultCallback.onResult(directories);
        }
    }

    private boolean contains(String path) {
        LogUtils.d(path);
        if (TextUtils.isEmpty(mSuffixRegex)) {
            return true;
        }
        String name = HFileUtils.extractFileNameWithSuffix(path);
        Pattern pattern = Pattern.compile(mSuffixRegex, Pattern.CASE_INSENSITIVE);
        Matcher matcher = pattern.matcher(name);
        return matcher.matches();
    }

    private String obtainSuffixRegex(String[] suffixes) {
        StringBuilder builder = new StringBuilder();
        for (int i = 0; i < suffixes.length; i++) {
            if (i == 0) {
                builder.append(suffixes[i].replace(".", ""));
            } else {
                builder.append("|\\.");
                builder.append(suffixes[i].replace(".", ""));
            }
        }
        return ".+(\\." + builder.toString() + ")$";
    }
}
